{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Title: #Predict the Winner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Difficulty: #Medium"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Category Title: #Algorithms"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tag Slug: #recursion #array #math #dynamic-programming #game-theory"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Name Translated: #递归 #数组 #数学 #动态规划 #博弈"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Solution Name: predictTheWinner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Translated Title: #预测赢家"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Translated Content:\n",
    "<p>给你一个整数数组 <code>nums</code> 。玩家 1 和玩家 2 基于这个数组设计了一个游戏。</p>\n",
    "\n",
    "<p>玩家 1 和玩家 2 轮流进行自己的回合，玩家 1 先手。开始时，两个玩家的初始分值都是 <code>0</code> 。每一回合，玩家从数组的任意一端取一个数字（即，<code>nums[0]</code> 或 <code>nums[nums.length - 1]</code>），取到的数字将会从数组中移除（数组长度减 <code>1</code> ）。玩家选中的数字将会加到他的得分上。当数组中没有剩余数字可取时，游戏结束。</p>\n",
    "\n",
    "<p>如果玩家 1 能成为赢家，返回 <code>true</code> 。如果两个玩家得分相等，同样认为玩家 1 是游戏的赢家，也返回 <code>true</code> 。你可以假设每个玩家的玩法都会使他的分数最大化。</p>\n",
    "\n",
    "<p>&nbsp;</p>\n",
    "\n",
    "<p><strong>示例 1：</strong></p>\n",
    "\n",
    "<pre>\n",
    "<strong>输入：</strong>nums = [1,5,2]\n",
    "<strong>输出：</strong>false\n",
    "<strong>解释：</strong>一开始，玩家 1 可以从 1 和 2 中进行选择。\n",
    "如果他选择 2（或者 1 ），那么玩家 2 可以从 1（或者 2 ）和 5 中进行选择。如果玩家 2 选择了 5 ，那么玩家 1 则只剩下 1（或者 2 ）可选。 \n",
    "所以，玩家 1 的最终分数为 1 + 2 = 3，而玩家 2 为 5 。\n",
    "因此，玩家 1 永远不会成为赢家，返回 false 。</pre>\n",
    "\n",
    "<p><strong>示例 2：</strong></p>\n",
    "\n",
    "<pre>\n",
    "<strong>输入：</strong>nums = [1,5,233,7]\n",
    "<strong>输出：</strong>true\n",
    "<strong>解释：</strong>玩家 1 一开始选择 1 。然后玩家 2 必须从 5 和 7 中进行选择。无论玩家 2 选择了哪个，玩家 1 都可以选择 233 。\n",
    "最终，玩家 1（234 分）比玩家 2（12 分）获得更多的分数，所以返回 true，表示玩家 1 可以成为赢家。</pre>\n",
    "\n",
    "<p>&nbsp;</p>\n",
    "\n",
    "<p><strong>提示：</strong></p>\n",
    "\n",
    "<ul>\n",
    "\t<li><code>1 &lt;= nums.length &lt;= 20</code></li>\n",
    "\t<li><code>0 &lt;= nums[i] &lt;= 10<sup>7</sup></code></li>\n",
    "</ul>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Description: [predict-the-winner](https://leetcode.cn/problems/predict-the-winner/description/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Solutions: [predict-the-winner](https://leetcode.cn/problems/predict-the-winner/solutions/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_cases = ['[1,5,2]', '[1,5,233,7]']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def predictTheWinner(self, nums: List[int]) -> bool:\n",
    "        length = len(nums)\n",
    "        dp = [0] * length\n",
    "        for i, num in enumerate(nums):\n",
    "            dp[i] = num\n",
    "        for i in range(length - 2, -1, -1):\n",
    "            for j in range(i + 1, length):\n",
    "                dp[j] = max(nums[i] - dp[j], nums[j] - dp[j - 1])\n",
    "\n",
    "        return dp[length - 1] >= 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def predictTheWinner(self, nums: List[int]) -> bool:\n",
    "\n",
    "        n = len(nums)\n",
    "        f = [[0] * n for _ in range(n)]\n",
    "\n",
    "        for i in range(n - 1, -1, - 1):\n",
    "            f[i][i] = nums[i]\n",
    "            for j in range(i + 1, n):\n",
    "                f[i][j] = max(nums[i] - f[i + 1][j], nums[j] - f[i][j - 1])\n",
    "        return f[0][n - 1] >= 0\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def predictTheWinner(self, nums: List[int]) -> bool:\n",
    "\n",
    "\n",
    "        # def total(start, end, turn):\n",
    "        #     if start == end:\n",
    "        #         return nums[start] * turn\n",
    "        #     scoreStart = nums[start] * turn + total(start + 1, end, -turn)\n",
    "        #     scoreend = nums[end] * turn + total(start, end - 1, -turn)\n",
    "        #     return max(scoreStart * turn, scoreend * turn) * turn\n",
    "        # return total(0, len(nums) - 1, 1) >= 0\n",
    "\n",
    "        n = len(nums)\n",
    "        dp = [0] * n\n",
    "        for i, num in enumerate(nums):\n",
    "            dp[i] = num\n",
    "        \n",
    "        for i in range(n -2, -1, -1):\n",
    "            for j in range(i + 1, n):\n",
    "                dp[j] = max(nums[i] - dp[j], nums[j] - dp[j - 1])\n",
    "        return dp[n - 1] >= 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from functools import lru_cache\n",
    "\n",
    "class Solution:\n",
    "    def predictTheWinner(self, nums: List[int]) -> bool:\n",
    "        @lru_cache(None)\n",
    "        def first(l, r):\n",
    "            if l==r:\n",
    "                return nums[l]\n",
    "            else:\n",
    "                return max(nums[l] + second(l+1, r), nums[r] + second(l, r-1))\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def second(l, r):\n",
    "            if l==r:\n",
    "                return 0\n",
    "            else:\n",
    "                return min(first(l+1, r), first(l, r-1))\n",
    "\n",
    "        return first(0, len(nums)-1) * 2 >=sum(nums)\n"
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 2
}
